package com.rayson.yututu.service.impl;

import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.rayson.yututu.exception.BusinessException;
import com.rayson.yututu.exception.ErrorCodeEnum;
import com.rayson.yututu.exception.ThrowUtils;
import com.rayson.yututu.model.entity.Picture;
import com.rayson.yututu.model.entity.Space;
import com.rayson.yututu.model.entity.User;
import com.rayson.yututu.model.req.space.analyze.*;
import com.rayson.yututu.model.vo.*;
import com.rayson.yututu.service.PictureService;
import com.rayson.yututu.service.SpaceAnalyzeService;
import com.rayson.yututu.service.SpaceService;
import com.rayson.yututu.service.UserService;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author: rayson
 * Description: 空间分析
 * Date: 2025-01-18 10:04
 */
@Service
public class SpaceAnalyzeServiceImpl implements SpaceAnalyzeService {

    @Resource
    private UserService userService;

    @Resource
    private SpaceService spaceService;

    @Resource
    private PictureService pictureService;


    @Override
    public SpaceUsageAnalyzeVO getSpaceUsageAnalyze(SpaceUsageAnalyzeReq spaceUsageAnalyzeReq, User loginUser) {
        // 校验权限
        this.checkSpaceAnalyzeAuth(spaceUsageAnalyzeReq, loginUser);
        QueryWrapper<Picture> queryWrapper = new QueryWrapper<>();
        // 填充公共参数
        this.fillAnalyzeQueryWrapper(spaceUsageAnalyzeReq, queryWrapper);
        // 查询公共空间或者全部空间
        if (spaceUsageAnalyzeReq.isQueryAll() || spaceUsageAnalyzeReq.isQueryPublic()) {
            queryWrapper.select("pic_size");
            List<Object> list = pictureService.getBaseMapper().selectObjs(queryWrapper);
            long usedSize = list.stream().mapToLong(obj -> Long.parseLong(obj.toString())).sum();
            long usedCount = list.size();
            SpaceUsageAnalyzeVO usageVO = new SpaceUsageAnalyzeVO();
            usageVO.setUsedSize(usedSize);
            usageVO.setMaxSize(null);
            usageVO.setUsageRate(null);
            usageVO.setPictureCount(usedCount);
            usageVO.setPictureCapacity(null);
            usageVO.setPictureUsageRate(null);
            return usageVO;
        }
        // 查询特定空间的使用情况
        String spaceId = spaceUsageAnalyzeReq.getSpaceId();
        Space space = spaceService.getById(spaceId);
        ThrowUtils.throwIf(Objects.isNull(space), ErrorCodeEnum.NOT_FOUND_ERROR, "空间不存在");
        SpaceUsageAnalyzeVO usageVO = new SpaceUsageAnalyzeVO();
        usageVO.setUsedSize(space.getTotalSize());
        usageVO.setMaxSize(space.getMaxSize());
        double usageRate = NumberUtil.round(space.getTotalSize() * 100.0 / space.getMaxSize(), 2).doubleValue();
        usageVO.setUsageRate(usageRate);
        usageVO.setPictureCount(space.getTotalCount());
        usageVO.setPictureCapacity(space.getMaxCount());
        double countRate = NumberUtil.round(space.getTotalCount() * 100.0 / space.getMaxCount(), 2).doubleValue();
        usageVO.setPictureUsageRate(countRate);
        return usageVO;
    }

    @Override
    public List<SpaceCategoryAnalyzeVO> getSpaceCategoryAnalyze(SpaceCategoryAnalyzeReq spaceCategoryAnalyzeReq, User loginUser) {
        // 校验权限
        this.checkSpaceAnalyzeAuth(spaceCategoryAnalyzeReq, loginUser);

        QueryWrapper<Picture> queryWrapper = new QueryWrapper<>();
        // 填充公共参数
        this.fillAnalyzeQueryWrapper(spaceCategoryAnalyzeReq, queryWrapper);
        // 使用mp的分组查询
        queryWrapper.select("category, count(category) as count, sum(pic_size) as totalSize")
                .groupBy("category");
        return pictureService.getBaseMapper().selectMaps(queryWrapper)
                .stream()
                .map(map -> {
                    String category = (String) map.get("category");
                    Long count = ((Number) map.get("count")).longValue();
                    Long totalSize = ((Number) map.get("totalSize")).longValue();
                    return new SpaceCategoryAnalyzeVO(category, count, totalSize);
                }).collect(Collectors.toList());
    }

    @Override
    public List<SpaceTagAnalyzeVO> getSpaceTagAnalyze(SpaceTagAnalyzeReq spaceTagAnalyzeReq, User loginUser) {
        // 校验权限
        this.checkSpaceAnalyzeAuth(spaceTagAnalyzeReq, loginUser);

        QueryWrapper<Picture> queryWrapper = new QueryWrapper<>();
        // 填充公共参数
        this.fillAnalyzeQueryWrapper(spaceTagAnalyzeReq, queryWrapper);
        // 查询所有符合条件的图片的标签属性
        queryWrapper.select("tags");
        List<String> tagsJsonList = pictureService.getBaseMapper().selectObjs(queryWrapper)
                .stream()
                .filter(ObjUtil::isNotNull)
                .map(Object::toString)
                .collect(Collectors.toList());
        // 解析标签属性
        Map<String, Long> tagMap = tagsJsonList.stream()
                .flatMap(tagsJson -> JSONUtil.toList(tagsJson, String.class).stream())
                .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
        // 按照使用次数排序
        return tagMap.entrySet().stream()
                .sorted((a, b) -> Long.compare(b.getValue(), a.getValue()))
                .map(entry -> new SpaceTagAnalyzeVO(entry.getKey(), entry.getValue()))
                .collect(Collectors.toList());
    }

    @Override
    public List<SpaceSizeAnalyzeVO> getSpaceSizeAnalyze(SpaceSizeAnalyzeReq spaceSizeAnalyzeReq, User loginUser) {
        // 校验权限
        this.checkSpaceAnalyzeAuth(spaceSizeAnalyzeReq, loginUser);

        QueryWrapper<Picture> queryWrapper = new QueryWrapper<>();
        // 填充公共参数
        this.fillAnalyzeQueryWrapper(spaceSizeAnalyzeReq, queryWrapper);
        // 查询所有符合条件的图片的大小
        queryWrapper.select("pic_size");
        List<Long> sizeList = pictureService.getBaseMapper().selectObjs(queryWrapper)
                .stream()
                .map(Long.class::cast)
                .collect(Collectors.toList());
        // 定义大小分段范围
        Map<String, Long> rangeMap = new LinkedHashMap<>();
        sizeList.forEach(size -> {
            if (size > 1024 * 1024) {
                rangeMap.put(">1MB", rangeMap.getOrDefault("1M以上", 0L) + 1);
            } else if (size > 500 * 1024) {
                rangeMap.put("500KB-1MB", rangeMap.getOrDefault("500KB-1MB", 0L) + 1);
            } else if (size > 100 * 1024) {
                rangeMap.put("100KB-500KB", rangeMap.getOrDefault("100KB-500KB", 0L) + 1);
            } else {
                rangeMap.put("<100KB", rangeMap.getOrDefault("<100KB", 0L) + 1);
            }
        });
        return rangeMap.entrySet().stream()
                .map(entry -> new SpaceSizeAnalyzeVO(entry.getKey(), entry.getValue()))
                .collect(Collectors.toList());
    }

    @Override
    public List<SpaceUserAnalyzeVO> getSpaceUserAnalyze(SpaceUserAnalyzeReq spaceUserAnalyzeReq, User loginUser) {
        // 校验权限
        this.checkSpaceAnalyzeAuth(spaceUserAnalyzeReq, loginUser);

        QueryWrapper<Picture> queryWrapper = new QueryWrapper<>();
        // 填充公共参数
        this.fillAnalyzeQueryWrapper(spaceUserAnalyzeReq, queryWrapper);
        String userId = spaceUserAnalyzeReq.getUserId();
        queryWrapper.eq(StrUtil.isNotBlank(userId), "user_id", userId);
        String timeDimension = spaceUserAnalyzeReq.getTimeDimension();
        switch (timeDimension) {
            case "day":
                queryWrapper.select("DATE_FORMAT(create_time,'%Y-%m-%d') as period", "count(*) as count");
                break;
            case "week":
                queryWrapper.select("YEARWEEK(create_time) as period", "count(*) as count");
                break;
            case "month":
                queryWrapper.select("DATE_FORMAT(create_time,'%Y-%m') as period", "count(*) as count");
                break;
            default:
                throw new BusinessException(ErrorCodeEnum.PARAM_ERROR, "不支持的时间维度");
        }
        queryWrapper.groupBy("period").orderByAsc("period");
        List<Map<String, Object>> periodMap = pictureService.getBaseMapper().selectMaps(queryWrapper);
        return periodMap.stream()
                .map(map -> {
                    String period = map.get("period").toString();
                    Long count = ((Number) map.get("count")).longValue();
                    return new SpaceUserAnalyzeVO(period, count);
                }).collect(Collectors.toList());
    }

    @Override
    public List<Space> getSpaceRankAnalyze(SpaceRankAnalyzeReq spaceRankAnalyzeReq, User loginUser) {
        // 校验权限，仅管理员可用
        ThrowUtils.throwIf(!userService.isAdmin(loginUser), ErrorCodeEnum.NO_AUTH);
        // 构造查询条件
        LambdaQueryWrapper<Space> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.select(Space::getId, Space::getSpaceName, Space::getUserId, Space::getTotalSize)
                .orderByDesc(Space::getTotalSize)
                .last("limit " + spaceRankAnalyzeReq.getTopN());
        return spaceService.list(queryWrapper);
    }

    /**
     * 校验空间分析权限*
     *
     * @param spaceAnalyzeReq 请求参数
     * @param loginUser       当前用户
     */
    private void checkSpaceAnalyzeAuth(SpaceAnalyzeReq spaceAnalyzeReq, User loginUser) {
        boolean queryPublic = spaceAnalyzeReq.isQueryPublic();
        boolean queryAll = spaceAnalyzeReq.isQueryAll();
        // 全空间分析及公共空间分析仅管理员可以使用
        if (queryAll || queryPublic) {
            ThrowUtils.throwIf(!userService.isAdmin(loginUser), ErrorCodeEnum.NO_AUTH);
        } else {
            // 分析特定空间，仅空间所有人或管理员可以使用
            String spaceId = spaceAnalyzeReq.getSpaceId();
            spaceService.checkSpace(spaceId, loginUser, false);
        }
    }

    private void fillAnalyzeQueryWrapper(SpaceAnalyzeReq spaceAnalyzeReq, QueryWrapper<Picture> queryWrapper) {
        String spaceId = spaceAnalyzeReq.getSpaceId();
        boolean queryPublic = spaceAnalyzeReq.isQueryPublic();
        boolean queryAll = spaceAnalyzeReq.isQueryAll();
        if (queryAll) {
            return;
        }
        if (queryPublic) {
            queryWrapper.isNull("space_id");
            return;
        }
        if (StrUtil.isNotBlank(spaceId)) {
            queryWrapper.eq("space_id", spaceId);
            return;
        }
        throw new BusinessException(ErrorCodeEnum.PARAM_ERROR, "未指定查询范围");
    }
}
